package utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import srw.Argument;
import srw.Dictionary;
import srw.Property;
import srw.Word;

/**
 * utils for reading XML-files.
 * not in use if {@link Dictionary} is not in use
 *
 */

public class XMLUtils {

	private static XPath _xpath = XPathFactory.newInstance().newXPath();
	
	public static HashMap<String, Vector<Word>> loadDictionaryMapFromXML(String path) {
		FileInputStream is;
		try {
			is = new FileInputStream(path);
			Node document = parseXml(is);
			NodeList nodes = getNodeList(document, "/properties/property");

			if (nodes == null) {
				System.err.println("can't create NodeList");
				return null;
			}

			HashMap<String, Vector <Word>> map = new HashMap<String, Vector <Word>>();
			
			for (int i = 0; i < nodes.getLength(); i++) {
				Node property = nodes.item(i);
				String name = XMLUtils.getAttributeValue(property, "name");
				String args = XMLUtils.getAttributeValue(property, "args");
				String props = XMLUtils.getAttributeValue(property, "props");

				Word word = new Word(name);
				
				if (args != null && !args.isEmpty()) {
					Vector<String> arguments = split(args, ",");
					for (String arg : arguments) {
						Argument a = new Argument();
						Vector<String> prs = split(arg, " ");
						for (String p : prs)
							a.addProperty(Property.getByName(p));
						word.addArgument(a);
					}
				}

				if (props != null && !props.isEmpty()) {
				Vector<String> prs = split(props, " ");
				for (String p : prs) {
					word.addProperty(Property.getByName(p));
				}
				}
				Vector<Word> existingWords = map.get(name);
				if (existingWords == null) {
					existingWords = new Vector<Word>();
					map.put(name, existingWords);
				}
				existingWords.add(word);
			}
			is.close();
			return map;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static Document parseXml(InputStream inputStream) {
        Document node = null;
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setExpandEntityReferences(false);
            factory.setValidating(false);
            node = factory.newDocumentBuilder().parse(inputStream);
        } catch (SAXException e) {
            e.printStackTrace();
            throw new RuntimeException("XML Input is not valid");
        } catch (ParserConfigurationException e) {
            throw new RuntimeException("Parser configuration error");
        } catch (IOException e) {
            throw new RuntimeException("File reading error");
        }
        return node;
    }

    public static NodeList getNodeList(Node node, String key) {
        NodeList result = null;
        try {
        	result =  (NodeList) _xpath.evaluate(key, node, XPathConstants.NODESET);
        } catch (XPathExpressionException e) {
			e.printStackTrace();
		}
        return result;
    }
    
    public static String getAttributeValue(Node node, String attribname) {
    	if (node == null)
    		return null;
        Node attr = node.getAttributes().getNamedItem(attribname);
        if(attr != null) {
            return attr.getNodeValue().trim();
        }
        return null;
    }
    
   public static Vector<String> split(String string, String delim) {
        
        Vector<String> vector = new Vector<String>();
        StringTokenizer stringTokenizer = new StringTokenizer(string, delim);
        while (stringTokenizer.hasMoreTokens()) {
            vector.addElement(stringTokenizer.nextToken().trim());
        }
        return vector;
        
    }
}
